package org.oep.jmingle;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;

/**
 * This is a mostly static class to abstract theuse of the complicated
 * Record Store API.
 * @author pmkilgo
 *
 */

class RecordStoreTools {

	// This object doesn't need to be instantiated
	private RecordStoreTools() {}
	
	/**
	 * Export a hashtable of mingles to the record store
	 * @param table, the hashtable to export
	 * @param recordName, the name of the record store
	 * @throws RecordStoreException
	 */
	public static void export(Hashtable table, String recordName) throws RecordStoreException {
		// Our data in memory should be up-to-date, so delete the record
		try {
			RecordStore.deleteRecordStore(recordName);
		}
		catch (RecordStoreException e) {
			
		}
		
		// Add the new one
		RecordStore rs = RecordStore.openRecordStore(recordName,true);
		
		Enumeration nodes = table.elements();
		
		while(nodes.hasMoreElements()) {
			MingleNode node = (MingleNode) nodes.nextElement();
			byte [] record = SimpleRecord.createRecord(node.getAddress(), node.getName(), System.currentTimeMillis());
			
			rs.addRecord(record, 0, record.length);
		}
		rs.closeRecordStore();
	}
	
	/**
	 * Delete a record store
	 * @param recordName, the name of a record store
	 * @throws RecordStoreException
	 */
	public static void delete(String recordName) throws RecordStoreException {
		RecordStore.deleteRecordStore(recordName);
		RecordStore rs = RecordStore.openRecordStore(recordName, true);
		rs.closeRecordStore();	
	}
	
	/**
	 * Count the number of records in a recurd store
	 * @param recordName, the name of the record
	 * @return number of detected records
	 * @throws RecordStoreException
	 */
	public static int countRecords(String recordName) throws RecordStoreException {
		RecordStore rs = RecordStore.openRecordStore(recordName,true);
		int num = rs.getNumRecords();
		rs.closeRecordStore();
		return num;
	}
	
	/**
	 * Load a record store into a hashtable
	 * @param recordName, the name of the record store to load
	 * @param table, the hashtable to load into
	 * @return true if successful, false if not
	 * @throws RecordStoreException
	 */
	public static boolean load(String recordName, Hashtable table) throws RecordStoreException {
		RecordStore rs = RecordStore.openRecordStore(recordName,true);
		RecordEnumeration enumerator = null;
		if(rs.getNumRecords() > 0) {
			try {
				enumerator = rs.enumerateRecords(null, null, false);
			}
			catch(Exception e) {
				if(rs != null)
					rs.closeRecordStore();
				System.err.println(e);
				return false;
			}
		}
		else {
			rs.closeRecordStore();
			return true;
		}
		while(enumerator.hasNextElement()) {
			byte [] record = enumerator.nextRecord();
			
			String name = SimpleRecord.getName(record);
			String address = SimpleRecord.getAddress(record);
			long time = SimpleRecord.getTime(record);
			
			MingleNode n = new MingleNode(name, address);
			n.setLastSeen(time);
			table.put(address, n);
		}
		rs.closeRecordStore();
		return true;
	}
	
	/**
	 * Updates a record with data from a mingle node
	 * @param node
	 * @param recordName
	 * @return true if successful, false if not (currently it's always successful :P)
	 * @throws RecordStoreException
	 */
	public static boolean update(MingleNode node, String recordName) throws RecordStoreException {
		RecordStore rs = RecordStore.openRecordStore(recordName,true);
		
		if(rs.getNumRecords() <= 0) {
			rs.closeRecordStore();
			RecordStoreTools.add(node, recordName);
			return true;
		}

			
		byte [] newRecord = SimpleRecord.createRecord(node.getAddress(), node.getName(), node.getLastSeen());
		for(int recID = 1; recID <= rs.getNumRecords(); recID++) {
			byte [] record = rs.getRecord(recID);
			String addy = SimpleRecord.getAddress(record);
			if(node.getAddress().compareTo(addy) == 0){
				rs.setRecord(recID, newRecord, 0, newRecord.length);
				rs.closeRecordStore();
				return true;
			}
		}
		rs.closeRecordStore();
		RecordStoreTools.add(node, recordName);
		return true;
	}
	
	/**
	 * Add a node to a record store.
	 * @param node
	 * @param recordName
	 * @throws RecordStoreException
	 */
	public static void add(MingleNode node, String recordName) throws RecordStoreException {
		RecordStore rs = RecordStore.openRecordStore(recordName,true);
		byte [] newRecord = SimpleRecord.createRecord(node.getAddress(), node.getName(), node.getLastSeen());
		rs.addRecord(newRecord, 0, newRecord.length);
		rs.closeRecordStore();
	}
	
	/**
	 * Retrieve a record by way of the device address
	 * @param recordName
	 * @param address
	 * @return a byte-array representing the record
	 * @throws RecordStoreException
	 */
	public static byte[] fetchRecord(String recordName, String address) throws RecordStoreException {
		RecordStore rs = RecordStore.openRecordStore(recordName,true);
		RecordEnumeration enumerator = null;
		if(rs.getNumRecords() > 0) {
			try {
				enumerator = rs.enumerateRecords(null, null, false);
			}
			catch(Exception e) {
				if(rs != null)
					rs.closeRecordStore();
				System.out.println(e);
				return null;
			}
		}
		else {
			rs.closeRecordStore();
			return null;
		}
		
		while(enumerator.hasNextElement()) {
			byte [] record = enumerator.nextRecord();
			String addy = SimpleRecord.getAddress(record);
			if(address.compareTo(addy) == 0){
				rs.closeRecordStore();
				return record;
			}
		}
		rs.closeRecordStore();
		return null;
	}	
	
	/**
	 * Fetch from the record store looking for a long value stored as ASCII at a particular index
	 * @param name
	 * @param index
	 * @return the long value found
	 * @throws RecordStoreException
	 */
	public static long fetchLong(String name, int index) throws RecordStoreException {
			RecordStore rs = RecordStore.openRecordStore(name,true);
			byte [] data;
			data = rs.getRecord(index);
			rs.closeRecordStore();
			
			// What's going on?
			// The number is stored as ascii, so we need to retrieve it and convert it
			// back into a long value
			long a = 0;
			for(int i = 0; i < data.length; i++) {
				byte num = data[i];
				if(num >= '0' && num <= '9') {
					a *= 10;
					a += num - '0';
				}
			}
			
			System.out.println("I think the num is: " + a);
			return a;
	}
	
	/**
	 * Overwrite a record at a specified index with a long value
	 * @param name, the record store to write to
	 * @param index, where to write the value
	 * @param num, the value to write
	 * @throws RecordStoreException
	 */
	public static void storeLong(String name, int index, long num)
	throws RecordStoreException {
		byte [] data = String.valueOf(num).getBytes();
		// Try and open the record store
		RecordStore rs = RecordStore.openRecordStore(name, true);
		rs.setRecord(index, data, 0, data.length);
		rs.closeRecordStore();
	}
	
	/**
	 * Add a long value to the record store
	 * @param name, the record store to write to
	 * @param num, the value to write
	 * @throws RecordStoreException
	 */
	public static void addLong(String name, long num)
	throws RecordStoreException {
		byte [] data = String.valueOf(num).getBytes();
		RecordStore rs = RecordStore.openRecordStore(name, true);
		rs.addRecord(data, 0, data.length);
		rs.closeRecordStore();
	}
}



